Skip to content

Comments

Add FTP integration improvements#718

Merged
NipunaRanasinghe merged 18 commits intoballerina-platform:1.7.xfrom
niveathika:ftp-improvements-main
Feb 20, 2026
Merged

Add FTP integration improvements#718
NipunaRanasinghe merged 18 commits intoballerina-platform:1.7.xfrom
niveathika:ftp-improvements-main

Conversation

@niveathika
Copy link
Contributor

@niveathika niveathika commented Feb 18, 2026

Summary

Ports FTP integration improvements to main.

Included changes

  • Add FTP post-process actions for success/error handlers
  • Filter deprecated listener config members from listener model generation
  • Add related checkstyle/spotbugs/test updates
  • Fix FTP function annotation parsing by using the same function-node extraction path as databinding

Validation

  • ./gradlew :service-model-generator:service-model-generator-ls-extension:compileJava -x spotbugsMain

FTP Integration Improvements

Overview

Ports FTP integration enhancements to main to improve service-model generation and UI configurability by adding annotation-driven post-processing, excluding deprecated listener configuration members from generated models, and aligning function-node extraction with databinding for consistent annotation handling.

Key changes

  • FTP post-processing

    • Adds FTPFunctionBuilder and wires FTP into function builder routing.
    • Merges a JSON-based FTP function template into generated functions and supports configurable post-process actions for onSuccess and onError with Move/Delete choices (including move destination).
    • FTPServiceBuilder reads and applies function-level post-process configuration from annotations, supports a service-level @ftp:ServiceConfig, and improves listener selection and service-init flows.
  • Deprecation handling

    • Adds a deprecated flag to ParameterData and propagates it through FunctionDataBuilder.
    • ListenerDeclAnalyzer and ListenerUtil skip deprecated parameters so deprecated options are omitted from generated listener models and UI.
  • Function & model processing

    • Adds ServiceModelUtils.extractFunctionNodesFromSource to return FunctionDefinitionNode lists and uses it to align function-node extraction with databinding parsing.
    • Filters legacy listener declarations and detects compatible listeners during service-init model generation.
  • Templates, resources & versioning

    • Updates FTP service/init JSON and multiple service-model test fixtures to 2.17.0.
    • Adds annotServiceConfig and a postProcessAction schema across FTP function definitions and test resources.
  • Tests & tooling

    • Re-enables test fixture update persistence in several test failure branches to keep fixtures in sync.
    • Applies related Checkstyle, SpotBugs, and test updates.
    • Validation: ./gradlew :service-model-generator:service-model-generator-ls-extension:compileJava -x spotbugsMain

Files of note

  • Added: service-model-generator/.../function/FTPFunctionBuilder.java
  • Modified: FTPServiceBuilder, FunctionBuilderRouter, ServiceModelUtils, ListenerDeclAnalyzer, ListenerUtil, FunctionDataBuilder, ParameterData, DatabaseManager, ServiceDatabaseManager
  • Resources & tests: services/ftp_service.json, services/ftp_init.json, multiple test JSONs and tests

Intent / Outcome

Improve FTP service-model generation and editor experience by enabling configurable, annotation-driven post-processing, reducing deprecated configuration noise in generated models, and ensuring consistent function extraction and databinding parsing.

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a deprecated flag to parameter metadata and propagates it through model-generator-commons; integrates FTP support (router wiring, FTPFunctionBuilder, FTPServiceBuilder) with JSON templates and annotation-driven postProcessAction handling; filters deprecated parameters from listener/property generation; updates FTP JSON schemas and re-enables tests to update expected configs on failure.

Changes

Cohort / File(s) Summary
Parameter metadata & builders
model-generator-commons/src/main/java/io/ballerina/modelgenerator/commons/ParameterData.java, .../DatabaseManager.java, .../ServiceDatabaseManager.java, .../FunctionDataBuilder.java
Added deprecated boolean to ParameterData and updated factory/constructor usages and builders to propagate the flag; FunctionDataBuilder now short-circuits from index and sets deprecation state when building parameter data.
Listener & property filtering
service-model-generator/.../util/ListenerDeclAnalyzer.java, .../util/ListenerUtil.java
Skip deprecated parameters in listener parameter iteration, rest-param handling, named/positional argument processing, and property population to prevent deprecated params from appearing in generated properties.
FTP integration: router + builders
service-model-generator/.../builder/FunctionBuilderRouter.java, .../builder/function/FTPFunctionBuilder.java, .../builder/service/FTPServiceBuilder.java
Register FTP in router; add FTPFunctionBuilder to merge FTP JSON templates into function models and generate postProcessAction annotations; add FTPServiceBuilder to detect/reuse/create compatible listeners and apply service-level @ftp:ServiceConfig and post-process configuration.
Service model utilities
service-model-generator/.../util/ServiceModelUtils.java
Added extractFunctionNodesFromSource(ServiceDeclarationNode) and refactored function extraction to map nodes to Function models.
FTP JSON templates & init/configs
service-model-generator/.../resources/services/ftp_service.json, .../resources/services/ftp_init.json, service-model-generator/.../src/test/resources/**/ftp_service_model.json, .../get_service_init_model/**/ftp_service_model.json, .../get_sm_from_source/**/ftp_service_model.json
Bumped FTP service to 2.17.0; added top-level annotServiceConfig, new path (Monitoring Path), and extensive postProcessAction schema across functions; updated icons, package refs, and many JSON schema entries.
Test behavior: update-on-failure
service-model-generator/.../src/test/java/.../AddServiceAndListenerTest.java, GetServiceInitModelTest.java, GetServiceModelFromSourceTest.java
Re-enabled updateConfig(configJsonPath, updatedConfig) in test failure branches so expected configs are persisted/updated before asserting and failing.
Test resource adjustments
service-model-generator/.../src/test/resources/add_service_and_listener/config/ftp_service_model.json
Reworked listener config: moved service path into @ftp:ServiceConfig annotation, simplified listener constructor, renamed authenticationuserName + password, and adjusted metadata/values.
Architecture/util tweaks
architecture-model-generator/.../Artifact.java, .../CommonUtils.java
Added FTP annotation field mapping for service name extraction and broadened extractServiceAnnotationField to handle non-literal annotation field expressions.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Client/UI
    participant Router as FunctionBuilderRouter
    participant SBuilder as FTPServiceBuilder
    participant FBuilder as FTPFunctionBuilder
    participant Template as FTP JSON Template
    participant Store as ServiceModelStore

    UI->>Router: request build for FTP service
    Router->>SBuilder: select or create compatible listener & service config
    SBuilder->>Store: query existing listeners (compatibility)
    SBuilder->>SBuilder: decide reuse vs new listener, emit `@ftp:ServiceConfig` if needed
    Router->>FBuilder: route function build for FTP functions
    FBuilder->>Template: load ftp_service.json template
    FBuilder->>FBuilder: merge template into function model (params, return, postProcessAction)
    FBuilder->>Store: save/update function model and attach annotations
    Store-->>UI: return built service model (with postProcessAction + listener config)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Sync main with 1.6.x branch #712: Modifies FunctionDataBuilder/ParameterData construction and deprecation propagation; closely related to ParameterData/additional flag changes in this PR.

Suggested reviewers

  • KavinduZoysa

Poem

🐇 I hopped through JSON, templates in paw,

Merged FTP actions with a nimble jaw,
Deprecated crumbs I left behind,
New annotations and paths aligned,
A rabbit's cheer — models built, refined! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is incomplete relative to the template. It lacks Purpose, Goals, Approach, User stories, Release note, Documentation, Training, Certification, Marketing, Automation tests, Security checks, and other required sections. Complete the pull request description by filling in all required sections from the template, particularly Purpose (with issue links), Goals, Approach, Release notes, and Documentation impact assessment.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add FTP integration improvements' directly describes the main change—adding FTP functionality enhancements. It is clear, specific, and accurately reflects the primary objective of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java (1)

325-360: ⚠️ Potential issue | 🟠 Major

Fix function-node lookup to avoid collisions for resource functions sharing the same accessor.

The current map key using functionName().text() causes collisions when multiple resource functions share the same accessor (e.g., get("/users") and get("/products") both key to "get"). This can attach post-process annotations to the wrong function or skip them entirely.

Use line ranges instead, which are unique identifiers available in both the FunctionDefinitionNode and the sourceFunc.getCodedata():

🔧 Suggested fix
+import io.ballerina.tools.text.LineRange;
@@
-        Map<String, FunctionDefinitionNode> functionNodes = new HashMap<>();
-        for (FunctionDefinitionNode functionNode : extractFunctionNodesFromSource(serviceNode)) {
-            functionNodes.put(functionNode.functionName().text().trim(), functionNode);
-        }
+        Map<LineRange, FunctionDefinitionNode> functionNodes = new HashMap<>();
+        for (FunctionDefinitionNode functionNode : extractFunctionNodesFromSource(serviceNode)) {
+            functionNodes.put(functionNode.lineRange(), functionNode);
+        }
@@
-                        FunctionDefinitionNode functionNode = functionNodes.get(sourceFuncName);
+                        LineRange fnRange = sourceFunc.getCodedata() != null
+                                ? sourceFunc.getCodedata().getLineRange() : null;
+                        FunctionDefinitionNode functionNode = fnRange != null
+                                ? functionNodes.get(fnRange) : null;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`
around lines 325 - 360, The function-node lookup uses functionName().text() as
the map key which collides for resource functions with the same accessor; change
the keying in the population of functionNodes (from
extractFunctionNodesFromSource and FunctionDefinitionNode) to use a unique
line-range identifier (e.g., functionNode.lineRange().toString()) and when
looking up the node for a source Function use the
sourceFunc.getCodedata().getLineRange() (or its toString()) to retrieve the
correct FunctionDefinitionNode before calling
updatePostProcessActionsFromAnnotation; update all references to
functionNodes.put(...) and functionNodes.get(...) accordingly so lookups use
line ranges instead of functionName().text().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@model-generator-commons/src/main/java/io/ballerina/modelgenerator/commons/PackageUtil.java`:
- Around line 118-124: The code in getSemanticModel currently catches Throwable
from getModulePackage; change that to catch Exception instead and handle
interrupts properly: replace "catch (Throwable ignored)" with "catch (Exception
e)" then if (e instanceof InterruptedException) re-set the interrupt via
Thread.currentThread().interrupt(); finally return Optional.empty(); this keeps
getSemanticModel and getModulePackage references intact while avoiding
swallowing fatal Errors.

In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`:
- Around line 688-709: The compatibility scan in
isListenerCompatibleWithNewPattern only iterates the default module (variable
defaultModule) and will miss services in non-default modules; change the logic
to iterate all modules of the current package (or at minimum the listener's
owning module) instead of only defaultModule, and for each Module repeat the
existing DocumentId -> Document -> ModulePartNode -> members() scanning and
hasServiceConfigAnnotation checks so legacy services in non-default modules are
detected.
- Around line 636-643: The current suffix-only matcher in findAnnotationBySuffix
(used for endsWith("FunctionConfig") and endsWith("ServiceConfig")) can falsely
match annotations from other modules; instead resolve the annotation symbol via
the semantic model (or at least inspect the annotation's module
prefix/qualifier) and verify it belongs to the FTP module/namespace before
accepting it. Update findAnnotationBySuffix/its call sites to retrieve the
AnnotationNode's resolved symbol (via the semantic model APIs available in the
project) and confirm the symbol's module name/organization (or compare the
annotation's qualifier/alias) equals the FTP module identifier, returning the
annotation only on a positive match.

---

Outside diff comments:
In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`:
- Around line 325-360: The function-node lookup uses functionName().text() as
the map key which collides for resource functions with the same accessor; change
the keying in the population of functionNodes (from
extractFunctionNodesFromSource and FunctionDefinitionNode) to use a unique
line-range identifier (e.g., functionNode.lineRange().toString()) and when
looking up the node for a source Function use the
sourceFunc.getCodedata().getLineRange() (or its toString()) to retrieve the
correct FunctionDefinitionNode before calling
updatePostProcessActionsFromAnnotation; update all references to
functionNodes.put(...) and functionNodes.get(...) accordingly so lookups use
line ranges instead of functionName().text().

---

Duplicate comments:
In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/resources/services/ftp_service.json`:
- Around line 1044-1321: The JSON contains a duplicated postProcessAction schema
block; remove the redundant copy and keep a single canonical "postProcessAction"
definition (including its nested "onSuccess" and "onError" choices and "moveTo"
properties) so the model isn't duplicated. Locate the second "postProcessAction"
object within the service definition (the block that mirrors the earlier one)
and delete it, ensuring references to "postProcessAction", "onSuccess",
"onError", and the "moveTo" property remain defined only once and the
surrounding JSON remains valid.
- Around line 1349-1632: This block duplicates the existing postProcessAction
schema (properties.postProcessAction with nested onSuccess/onError choices and
moveTo fields); remove the duplicate definition or consolidate by referencing
the original schema instead so only one postProcessAction structure exists,
ensuring the parameter list and returnType remain unchanged and that symbols
like postProcessAction, onSuccess, onError, and moveTo are preserved exactly in
the single canonical definition.
- Around line 733-999: The JSON contains a duplicated postProcessAction schema
block; locate the second "postProcessAction" occurrence (property name
"postProcessAction" inside the service JSON and its nested "onSuccess"/"onError"
choices) and remove or replace it with a reference to the first canonical
definition to avoid duplication — either delete the repeated object entirely or
replace it with a shared schema reference (e.g., reuse the initial
postProcessAction object or point to a common definition key) so only one
authoritative "postProcessAction" structure remains.
- Around line 420-586: The postProcessAction block under properties is
duplicated (same structure as the earlier postProcessAction); remove the
redundant copy or refactor to a single reusable definition and replace the
duplicate with a reference. Locate the "postProcessAction" property object and
either delete the repeated instance or extract its schema into a shared
definition and point the second occurrence to that definition (using a $ref or
common properties) so there is a single authoritative schema for
postProcessAction.

Comment on lines 688 to 709
Module defaultModule = project.currentPackage().getDefaultModule();
for (DocumentId documentId : defaultModule.documentIds()) {
Document document = defaultModule.document(documentId);
ModulePartNode modulePartNode = document.syntaxTree().rootNode();

for (ModuleMemberDeclarationNode member : modulePartNode.members()) {
if (member.kind() != SyntaxKind.SERVICE_DECLARATION) {
continue;
}

ServiceDeclarationNode serviceNode = (ServiceDeclarationNode) member;
if (isServiceAttachedToListener(serviceNode, listenerName)) {
// Check if this service uses the new pattern (has @ftp:ServiceConfig annotation)
if (!hasServiceConfigAnnotation(serviceNode)) {
return false; // Legacy service found
}
}
}
}

return true; // No legacy services found
}
Copy link

@coderabbitai coderabbitai bot Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Compatibility scan ignores non-default modules.

isListenerCompatibleWithNewPattern only scans the default module. If legacy services or listeners live in non-default modules, they’ll be missed and the listener could be incorrectly classified as compatible. Consider iterating all modules (or the listener’s owning module) when scanning service declarations.

🔧 Possible fix (scan all modules)
-        Module defaultModule = project.currentPackage().getDefaultModule();
-        for (DocumentId documentId : defaultModule.documentIds()) {
-            Document document = defaultModule.document(documentId);
-            ModulePartNode modulePartNode = document.syntaxTree().rootNode();
+        for (Module module : project.currentPackage().modules()) {
+            for (DocumentId documentId : module.documentIds()) {
+                Document document = module.document(documentId);
+                ModulePartNode modulePartNode = document.syntaxTree().rootNode();
@@
-        }
+            }
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`
around lines 688 - 709, The compatibility scan in
isListenerCompatibleWithNewPattern only iterates the default module (variable
defaultModule) and will miss services in non-default modules; change the logic
to iterate all modules of the current package (or at minimum the listener's
owning module) instead of only defaultModule, and for each Module repeat the
existing DocumentId -> Document -> ModulePartNode -> members() scanning and
hasServiceConfigAnnotation checks so legacy services in non-default modules are
detected.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ATM, we do not expect any projects with non-default module. @samithkavishke Please confirm

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listenerSymbol.get().getLocation().get().lineRange() we can use this to find the document filePath and all the information

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`:
- Around line 595-609: The applyPostProcessAction method currently only handles
mapping constructors and a fragile suffix check for ACTION_DELETE; update it to
explicitly detect constant reference nodes so qualified and unqualified
MOVE/DELETE values are handled. Inside applyPostProcessAction, add instanceof
branches that check for QualifiedNameReferenceNode and SimpleNameReferenceNode
on valueExpr, extract the referenced identifier text, and call
selectPostProcessChoice(actionProperty, ACTION_MOVE, extractMoveProperties(...))
when the identifier equals ACTION_MOVE and
selectPostProcessChoice(actionProperty, ACTION_DELETE, null) when it equals
ACTION_DELETE; preserve the existing mapping constructor branch (mappingExpr)
and keep using extractMoveProperties for MOVE mapping handling. Ensure you
reference the constants ACTION_MOVE and ACTION_DELETE and reuse
selectPostProcessChoice and extractMoveProperties when applicable.

---

Duplicate comments:
In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`:
- Around line 705-732: The compatibility check in
isListenerCompatibleWithNewPattern currently scans only
project.currentPackage().getDefaultModule(), which misses services in other
modules; update the logic to iterate all modules in
project.currentPackage().modules() (or at least the module owning the listener
found via findListenerSymbol) and scan each Module's documentIds for
ServiceDeclarationNode entries, using existing helpers
isServiceAttachedToListener and hasServiceConfigAnnotation to determine
compatibility so legacy services in non-default modules are detected.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/resources/services/ftp_init.json`:
- Around line 625-656: The codedata for the "path" field currently sets
originalName to "ServiceConfig", which is incorrect for the Ballerina FTP
library; update the codedata.originalName value on the "path" field so it reads
"ListenerConfiguration" (i.e., locate the "path" object and change
codedata.originalName from "ServiceConfig" to "ListenerConfiguration" so
templates referencing ftp:ListenerConfiguration will work).
- Around line 8-10: Update the FTP metadata in ftp_init.json by changing the
"version" field value from "2.17.0" to "2.16.0" and update the "icon" URL
accordingly to
"https://bcentral-packageicons.azureedge.net/images/ballerina_ftp_2.16.0.png";
edit the keys "version" and "icon" in the JSON object shown in the diff so
metadata resolution and UI icon rendering use the published 2.16.0 package.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java (1)

221-274: Consider extracting listener declaration building to a helper method.

The listener declaration building logic (lines 221-274) is lengthy and handles multiple conditional paths. While functionally correct, extracting this to a dedicated buildListenerDeclaration method would improve readability and testability of addServiceInitSource.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`
around lines 221 - 274, Extract the long StringBuilder logic that constructs
listenerDeclaration into a new helper method named buildListenerDeclaration that
takes the required inputs (listenerVarName, selectedProtocol, host, username,
password, privateKey, secureSocket, port) and returns the built String; replace
the inlined block in addServiceInitSource with a single call like
listenerDeclaration = buildListenerDeclaration(...). Make the helper method
private (or private static) inside FTPServiceBuilder, move all conditional
branches and StringBuilder manipulation there unchanged, and ensure
addServiceInitSource imports/uses the returned String so behavior and variable
names (listenerVarName, listenerDeclaration) remain consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`:
- Around line 716-737: The compatibility scan in
isListenerCompatibleWithNewPattern only iterates the default module (Module
defaultModule = project.currentPackage().getDefaultModule()), so legacy services
in other modules are ignored; update the method to iterate all modules in the
package (e.g., for each Module module : project.currentPackage().modules()) and
then iterate each module.documentIds() and their ModulePartNode members, using
the same ServiceDeclarationNode checks and hasServiceConfigAnnotation/
isServiceAttachedToListener logic to ensure no legacy services in submodules are
missed.
- Around line 597-611: applyPostProcessAction currently only handles
MappingConstructorExpressionNode (for MOVE) and uses string suffix matching for
DELETE, missing cases where ACTION_MOVE/ACTION_DELETE are referenced as
QualifiedNameReferenceNode or SimpleNameReferenceNode (e.g., ftp:MOVE). Update
applyPostProcessAction to detect when valueExpr is a QualifiedNameReferenceNode
or SimpleNameReferenceNode, resolve the referenced identifier text (trim and
possibly include qualifier), and call selectPostProcessChoice(actionProperty,
ACTION_MOVE, extractMoveProperties(mappingExpr)) when the identifier equals
ACTION_MOVE, or selectPostProcessChoice(actionProperty, ACTION_DELETE, null)
when it equals ACTION_DELETE; keep existing MappingConstructorExpressionNode
handling and string fallback as a last resort. Ensure you reference the
constants ACTION_MOVE and ACTION_DELETE and reuse extractMoveProperties and
selectPostProcessChoice.

---

Nitpick comments:
In
`@service-model-generator/modules/service-model-generator-ls-extension/src/main/java/io/ballerina/servicemodelgenerator/extension/builder/service/FTPServiceBuilder.java`:
- Around line 221-274: Extract the long StringBuilder logic that constructs
listenerDeclaration into a new helper method named buildListenerDeclaration that
takes the required inputs (listenerVarName, selectedProtocol, host, username,
password, privateKey, secureSocket, port) and returns the built String; replace
the inlined block in addServiceInitSource with a single call like
listenerDeclaration = buildListenerDeclaration(...). Make the helper method
private (or private static) inside FTPServiceBuilder, move all conditional
branches and StringBuilder manipulation there unchanged, and ensure
addServiceInitSource imports/uses the returned String so behavior and variable
names (listenerVarName, listenerDeclaration) remain consistent.

Comment on lines +93 to +101
@Override
public Function getModelFromSource(ModelFromSourceContext context) {
Function functionModel = super.getModelFromSource(context);
if (context.node() instanceof FunctionDefinitionNode functionNode) {
functionModel = mergeWithTemplate(functionNode, functionModel);
updatePostProcessActionsFromAnnotation(functionNode, functionModel);
}
return functionModel;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check whether this function is being used or not?

Copy link
Contributor

@samithkavishke samithkavishke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few places that need to be updated, but it was approved in alpha with a few issues.

@LakshanWeerasinghe LakshanWeerasinghe changed the base branch from main to 1.7.x February 20, 2026 07:20
* Represents the FTP function builder of the service model generator.
* Handles post-processing actions for FTP functions.
*
* @since 1.5.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @since 1.5.0
* @since 1.7.0

@NipunaRanasinghe NipunaRanasinghe merged commit 53f4a3a into ballerina-platform:1.7.x Feb 20, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants